﻿using System.Collections.Generic;
using System.Linq;
using CID.Domain.Operations;
using System.ComponentModel.DataAnnotations;
using Newtonsoft.Json;

namespace CID.Web.Models.Operations
{
    public class ServerViewModel : BaseNamedViewModel<IServer>, IAjaxEnabledViewModel
    {
        #region Properties
        [Required(ErrorMessage = "You must provide an Address")]
        public string Address { get; set; }
        public bool Enabled { get; set; }

        [Required(ErrorMessage = "You must provide a Location")]
        public int? LocationId { get; set; }
        public string Location { get; set; }

        public List<ServerAssignmentViewModel> Assignments { get; set; }

        public string PostUrl { get; set; }
        #endregion

        public ServerViewModel() : base() 
        {
            Assignments = new List<ServerAssignmentViewModel>();
        }

        public ServerViewModel(IServer model) : base(model)
        {
            Assignments = new List<ServerAssignmentViewModel>();
            Enabled = model.Enabled;
            Address = model.Address;
            if (model.Location != null)
            {
                LocationId = model.Location.Id;
                Location = model.Location.Name;
            }

            foreach (var assignment in model.Assignments)
                Assignments.Add(new ServerAssignmentViewModel(assignment));
        }

        public override void UpdateModel(IServer model)
        {
            base.UpdateModel(model);

            model.Enabled = Enabled;
            model.Address = Address;
            model.Location = availableLocations.SingleOrDefault(x => x.Id == LocationId.Value);

            foreach (var removedAssignment in RemovedAssignments)
            {
                var assignment = model.Assignments.SingleOrDefault(x => x.Id == removedAssignment.Id);
                model.RemoveAssignment(assignment);
            }

            foreach (var insertedAssignment in InsertedAssignments)
                model.Assign(GetEnvironment(insertedAssignment), GetServerRole(insertedAssignment));
        }

        private IEnumerable<ServerAssignmentViewModel> InsertedAssignments
        {
            get { return Assignments.Where(x => ((x.Id == 0) && !x._destroy)); }
        }

        private IEnumerable<ServerAssignmentViewModel> RemovedAssignments
        {
            get { return Assignments.Where(x => ((x.Id != 0) && x._destroy)); }
        }

        #region Edition Helper Members

        #region Location helper members
        private IEnumerable<Location> availableLocations;

        public void SetAvailableLocations(IEnumerable<Location> availableLocations)
        {
            this.availableLocations = availableLocations.ToArray();
        }

        [JsonIgnore]
        public IEnumerable<LocationViewModel> AvailableLocations
        {
            get { return availableLocations.Select(x => new LocationViewModel(x)); }
        }
        #endregion

        #region ServerRole helper members
        private IEnumerable<ServerRole> availableServerRoles;

        public void SetAvailableServerRoles(IEnumerable<ServerRole> availableServerRoles)
        {
            this.availableServerRoles = availableServerRoles.ToArray();
        }
        #endregion

        #region Environment helper members
        private IEnumerable<Environment> availableEnvironments;

        public void SetAvailableEnvironments(IEnumerable<Environment> availableEnvironments)
        {
            this.availableEnvironments = availableEnvironments.ToArray();
        }
        #endregion

        public ServerAssignmentViewModel NewServerAssignment()
        {
            var result = new ServerAssignmentViewModel();
            result.SetAvailableEnvironments(availableEnvironments);
            result.SetAvailableServerRoles(availableServerRoles);

            return result;
        }

        private IEnvironment GetEnvironment(ServerAssignmentViewModel assignment)
        {
            return availableEnvironments.SingleOrDefault(x => x.Id == assignment.EnvironmentId);
        }

        private IServerRole GetServerRole(ServerAssignmentViewModel assignment)
        {
            return availableServerRoles.SingleOrDefault(x => x.Id == assignment.ServerRoleId);
        }
        #endregion
    }
}
